home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / Reference / DevCon / Orlando_1993 / Devcon93.1 / AREXX / SimpleRexx / SimpleRexx.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-11  |  9.9 KB  |  379 lines

  1. /*
  2.  *
  3.  * Toolmaker Simple ARexx interface... (SAS version)
  4.  *
  5.  * This is a very "Simple" interface to the world of ARexx...
  6.  * For more complex interfaces into ARexx, it is best that you
  7.  * understand the functions that are provided by ARexx.
  8.  * In many cases they are more powerful than what is presented
  9.  * here.
  10.  *
  11.  * This code is fully re-entrant and self-contained other than
  12.  * the use of SysBase/AbsExecBase and the ARexx RVI support
  13.  * library which is also self-contained...
  14.  *
  15.  * Appends .1, .2, etc. to requested portname as specified in Style Guide
  16.  *
  17. */
  18.  
  19. #include    <exec/types.h>
  20. #include    <exec/nodes.h>
  21. #include    <exec/lists.h>
  22. #include    <exec/ports.h>
  23. #include    <exec/memory.h>
  24.  
  25. #include    <clib/exec_protos.h>
  26. #include    <clib/rexxsyslib_protos.h>
  27. #include    <clib/alib_protos.h>
  28.  
  29. #include    <rexx/storage.h>
  30. #include    <rexx/rxslib.h>
  31.  
  32. #include    <stdio.h>
  33. #include    <string.h>
  34. #include    <ctype.h>
  35.  
  36. /*
  37.  * Pragmas for the above functions...  (To make this all self-contained...)
  38.  * If you use at least 2.04 amiga.lib, this is not needed...
  39. */
  40.  
  41. #pragma libcall RexxContext->RexxSysBase CreateRexxMsg 90 09803
  42. #pragma libcall RexxContext->RexxSysBase CreateArgstring 7E 0802
  43. #pragma libcall RexxContext->RexxSysBase DeleteRexxMsg 96 801
  44. #pragma libcall RexxContext->RexxSysBase DeleteArgstring 84 801
  45. #pragma libcall RexxContext->RexxSysBase IsRexxMsg A8 801
  46.  
  47. /*
  48.  * A structure for the ARexx handler context
  49.  * This is *VERY* *PRIVATE* and should not be touched...
  50. */
  51.  
  52. struct ARexxContext
  53.   {
  54.   struct MsgPort *ARexxPort;    /* The port messages come in at... */
  55.   struct Library *RexxSysBase;    /* We will hide the library pointer here... */
  56.   long Outstanding;        /* The count of outstanding ARexx messages... */
  57.   char PortName[24];        /* The port name goes here... */
  58.   char ErrorName[28];        /* The name of the <base>.LASTERROR... */
  59.   char Extension[8];        /* Default file name extension... */
  60.   };
  61.  
  62. #define    AREXXCONTEXT    struct ARexxContext *
  63.  
  64. #include "SimpleRexx.h"
  65.  
  66. /*
  67.  * This function returns the port name of your ARexx port.
  68.  * It will return NULL if there is no ARexx port...
  69.  *
  70.  * This string is *READ ONLY*  You *MUST NOT* modify it...
  71. */
  72.  
  73. char *ARexxName(AREXXCONTEXT RexxContext)
  74.   {
  75.   register char *tmp=NULL;
  76.  
  77.   if (RexxContext) tmp=RexxContext->PortName;
  78.  
  79.   return(tmp);
  80.   }
  81.  
  82. /*
  83.  * This function returns the signal mask that the Rexx port is
  84.  * using.  It returns NULL if there is no signal...
  85.  *
  86.  * Use this signal bit in your Wait() loop...
  87. */
  88.  
  89. ULONG ARexxSignal(AREXXCONTEXT RexxContext)
  90.   {
  91.   register ULONG tmp=NULL;
  92.  
  93.   if (RexxContext) tmp=1L << (RexxContext->ARexxPort->mp_SigBit);
  94.  
  95.   return(tmp);
  96.   }
  97.  
  98. /*
  99.  * This function returns a structure that contains the commands sent from
  100.  * ARexx...  You will need to parse it and return the structure back
  101.  * so that the memory can be freed...
  102.  *
  103.  * This returns NULL if there was no message...
  104. */
  105.  
  106. struct RexxMsg *GetARexxMsg(AREXXCONTEXT RexxContext)
  107.   {
  108.   register struct RexxMsg *tmp=NULL;
  109.   register short flag;
  110.  
  111.   if (RexxContext)
  112.     {
  113.     if (tmp=(struct RexxMsg *)GetMsg(RexxContext->ARexxPort))
  114.       {
  115.       if (tmp->rm_Node.mn_Node.ln_Type==NT_REPLYMSG)
  116.         {
  117.     /*
  118.      * If we had sent a command, it would come this way...
  119.      *
  120.      * Since we don't in this simple example, we just throw
  121.      * away anything that looks "strange"
  122.      */
  123.  
  124.         flag=FALSE;
  125.         if (tmp->rm_Result1) flag=TRUE;
  126.  
  127.         /* Free the arguments and the message... */
  128.  
  129.         DeleteArgstring(tmp->rm_Args[0]);
  130.         DeleteRexxMsg(tmp);
  131.         RexxContext->Outstanding-=1;
  132.  
  133.         /* Return the error if there was one... */
  134.  
  135.         tmp=flag ? REXX_RETURN_ERROR : NULL;
  136.         }
  137.       }
  138.     }
  139.  
  140.   return(tmp);
  141.   }
  142.  
  143. /*
  144.  * Use this to return a ARexx message...
  145.  *
  146.  * If you wish to return something, it must be in the RString.
  147.  * If you wish to return an Error, it must be in the Error.
  148.  * If there is an error, the RString is ignored.
  149. */
  150.  
  151. void ReplyARexxMsg(AREXXCONTEXT RexxContext,struct RexxMsg *rmsg,
  152.                    char *RString,LONG Error)
  153.   {
  154.   if ((RexxContext) && (rmsg) && (rmsg!=REXX_RETURN_ERROR))
  155.     {
  156.     rmsg->rm_Result2=0;
  157.     if (!(rmsg->rm_Result1=Error))
  158.       {
  159.       /* if you did not have an error we return the string */
  160.  
  161.       if ((rmsg->rm_Action & (1L << RXFB_RESULT)) && (RString))
  162.         {
  163.         rmsg->rm_Result2=(LONG)CreateArgstring(RString,(LONG)strlen(RString));
  164.         }
  165.       }
  166.  
  167.     /* Reply the message to ARexx... */
  168.  
  169.     ReplyMsg((struct Message *)rmsg);
  170.     }
  171.   }
  172.  
  173. /*
  174.  * This function will set an error string for the ARexx
  175.  * application in the variable defined as <appname>.LASTERROR
  176.  *
  177.  * Note that this can only happen if there is an ARexx message...
  178.  *
  179.  * This returns TRUE if it worked, FALSE if it did not...
  180. */
  181.  
  182. short SetARexxLastError(AREXXCONTEXT RexxContext,struct RexxMsg *rmsg,
  183.                         char *ErrorString)
  184.   {
  185.   register short OkFlag=FALSE;
  186.  
  187.   if (RexxContext && rmsg && CheckRexxMsg((struct Message *)rmsg))
  188.     {
  189.     /* Note that SetRexxVar() has more than just a TRUE/FALSE  */
  190.     /* return code, but for this "basic" case, we just care if */
  191.     /* it works or not.                                        */
  192.  
  193.     if (!SetRexxVar((struct Message *)rmsg,RexxContext->ErrorName,ErrorString,(long)strlen(ErrorString)))
  194.       {
  195.       OkFlag=TRUE;
  196.       }
  197.     }
  198.  
  199.   return(OkFlag);
  200.   }
  201.  
  202. /*
  203.  * This function will send a string to ARexx...
  204.  *
  205.  * The default host port will be that of your task...
  206.  *
  207.  * If you set StringFile to TRUE, it will set that bit for the message...
  208.  *
  209.  * Returns TRUE if it send the message, FALSE if it did not...
  210. */
  211.  
  212. short SendARexxMsg(AREXXCONTEXT RexxContext,char *RString,short StringFile)
  213.   {
  214.   register struct MsgPort *RexxPort;
  215.   register struct RexxMsg *rmsg;
  216.   register short flag=FALSE;
  217.  
  218.   if ((RexxContext) && (RString))
  219.     {
  220.     if (rmsg=CreateRexxMsg(RexxContext->ARexxPort, RexxContext->Extension,
  221.                     RexxContext->PortName))
  222.       {
  223.       rmsg->rm_Action=RXCOMM | (StringFile ? (1L << RXFB_STRING):0);
  224.       if (rmsg->rm_Args[0]=CreateArgstring(RString,(LONG)strlen(RString)))
  225.         {
  226.         /* We need to find the RexxPort; this needs to be done in a Forbid() */
  227.         Forbid();
  228.         if(RexxPort=FindPort(RXSDIR))
  229.           {
  230.           /* We found the port, so put the message to ARexx... */
  231.           PutMsg(RexxPort,(struct Message *)rmsg);
  232.           RexxContext->Outstanding+=1;
  233.           flag=TRUE;
  234.           }
  235.     Permit();
  236.  
  237.         if(!RexxPort)
  238.           {
  239.           /* No port, so clean up... */
  240.           DeleteArgstring(rmsg->rm_Args[0]);
  241.           DeleteRexxMsg(rmsg);
  242.           }
  243.         }
  244.       else
  245.         {
  246.         DeleteRexxMsg(rmsg);
  247.         }
  248.       }
  249.     }
  250.  
  251.   return(flag);
  252.   }
  253.  
  254. /* This function closes down the ARexx context opened with InitARexx... */
  255.  
  256. void FreeARexx(AREXXCONTEXT RexxContext)
  257.   {
  258.   register struct RexxMsg *rmsg;
  259.  
  260.   if (RexxContext)
  261.     {
  262.     /* Clear port name so it can't be found... */
  263.  
  264.     RexxContext->PortName[0]='\0';
  265.  
  266.     /* Clean out any outstanding messages we had sent out... */
  267.  
  268.     while (RexxContext->Outstanding)
  269.       {
  270.       WaitPort(RexxContext->ARexxPort);
  271.       while (rmsg=GetARexxMsg(RexxContext))
  272.         {
  273.         if (rmsg!=REXX_RETURN_ERROR)
  274.           {
  275.           /* Any messages that come now are blown away... */
  276.  
  277.           SetARexxLastError(RexxContext,rmsg,"99: Port Closed!");
  278.           ReplyARexxMsg(RexxContext,rmsg,NULL,100);
  279.           }
  280.         }
  281.       }
  282.  
  283.     /* Clean up the port and delete it... */
  284.  
  285.     if (RexxContext->ARexxPort)
  286.       {
  287.       while (rmsg=GetARexxMsg(RexxContext))
  288.         {
  289.         /* Any messages that still are coming in are "dead"       */
  290.         /* We just set the LASTERROR and reply an error of 100... */
  291.  
  292.         SetARexxLastError(RexxContext,rmsg,"99: Port Closed!");
  293.         ReplyARexxMsg(RexxContext,rmsg,NULL,100);
  294.         }
  295.       DeletePort(RexxContext->ARexxPort);
  296.       }
  297.  
  298.     /* Make sure we close the library... */
  299.  
  300.     if (RexxContext->RexxSysBase) CloseLibrary(RexxContext->RexxSysBase);
  301.  
  302.     /* Free the memory of the RexxContext */
  303.  
  304.     FreeMem(RexxContext,sizeof(struct ARexxContext));
  305.     }
  306.   }
  307.  
  308. /*
  309.  * This routine initializes an ARexx port for your process
  310.  * This should only be done once per process.  You must call it
  311.  * with a valid application name and you must use the handle it
  312.  * returns in all other calls...
  313.  *
  314.  * NOTE:  The AppName should not have spaces in it...
  315.  *        Example AppNames:  "MyWord" or "FastCalc" etc...
  316.  *        The name *MUST* be less that 16 characters...
  317.  *        If it is not, it will be trimmed...
  318.  *        The name will also be UPPER-CASED...
  319.  *
  320.  * NOTE:  The Default file name extension, if NULL will be
  321.  *        "rexx"  (the "." is automatic)
  322.  */
  323.  
  324. AREXXCONTEXT InitARexx(char *AppName,char *Extension)
  325.   {
  326.   register AREXXCONTEXT RexxContext=NULL;
  327.   register short loop;
  328.   register short count;
  329.   register char *tmp;
  330.  
  331.   if (RexxContext=AllocMem(sizeof(struct ARexxContext),MEMF_PUBLIC|MEMF_CLEAR))
  332.     {
  333.     if (RexxContext->RexxSysBase=OpenLibrary("rexxsyslib.library",NULL))
  334.       {
  335.       /* Set up the extension... */
  336.  
  337.       if (!Extension) Extension="rexx";
  338.  
  339.       tmp=RexxContext->Extension;
  340.       for (loop=0;(loop<7)&&(Extension[loop]);loop++) *tmp++=Extension[loop];
  341.       *tmp='\0';
  342.  
  343.       /* Set up a port name... */
  344.  
  345.       tmp=RexxContext->PortName;
  346.       for (loop=0;(loop<16)&&(AppName[loop]);loop++) *tmp++=toupper(AppName[loop]);
  347.       *tmp='\0';
  348.  
  349.       /* Set up the last error RVI name... This is <appname>.LASTERROR */
  350.  
  351.       strcpy(RexxContext->ErrorName,RexxContext->PortName);
  352.       strcat(RexxContext->ErrorName,".LASTERROR");
  353.  
  354.       /* We need to make a unique port name... */
  355.  
  356.       Forbid();
  357.  
  358.       for (count=1,RexxContext->ARexxPort=(VOID *)1;
  359.            RexxContext->ARexxPort; count++)
  360.         {
  361.         sprintf(tmp,".%ld",count);
  362.         RexxContext->ARexxPort=FindPort(RexxContext->PortName);
  363.         }
  364.  
  365.       RexxContext->ARexxPort=CreatePort(RexxContext->PortName,NULL);
  366.  
  367.       Permit();
  368.       }
  369.  
  370.     if ((!(RexxContext->RexxSysBase)) || (!(RexxContext->ARexxPort)))
  371.       {
  372.       FreeARexx(RexxContext);
  373.       RexxContext=NULL;
  374.       }
  375.     }
  376.  
  377.   return(RexxContext);
  378.   }
  379.